package com.ns.dcjh.utils;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.format.DateUtils;
import android.util.Base64;
import android.util.Log;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.util.Util;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.schedulers.Schedulers;

public class BitmapUtils {

    /**
     * base64转bitmap
     *
     * @param base64Str
     * @return
     */
    public static Bitmap base64ToBitmap(String base64Str, Context mContext) {
        try {
            byte[] bytes = Base64.decode(base64Str, Base64.DEFAULT);
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        } catch (Exception e) {
            ToastUtils.info(mContext, "base64转bitmap出错==>" + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    public static Bitmap compressBitmap(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(format, quality, stream);
        byte[] byteArray = stream.toByteArray();

        // 从字节流中解码生成新的Bitmap对象
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
    }

    /**
     * bitmap转base64
     *
     * @param bitmap
     * @return
     */
    public static String bitmapToBase64(Bitmap bitmap, Context mContext) {
        String result = null;
        ByteArrayOutputStream outputStream = null;

        try {
            if (bitmap == null) throw new Exception("BitMap为空");
            outputStream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
            outputStream.flush();
            outputStream.close();

            byte[] byteArray = outputStream.toByteArray();
            result = Base64.encodeToString(byteArray, Base64.DEFAULT);
        } catch (Exception e) {
            ToastUtils.info(mContext, "bitmap转Base64出错==>" + e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.flush();
                    outputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static Bitmap getBitmapForUrlOrBase64(Context context, String data) {
        Bitmap bitmap = null;
        if (data != null && data.substring(0, 4).equals("http")) {
            try {
                bitmap = Glide.with(context)
                        .asBitmap()
                        .load(data)
                        .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
                        .get();
            } catch (Exception e) {
                ToastUtils.info(context, "Glide加载Bitmap出错==>" + e.getMessage());
                e.printStackTrace();
            }
        } else {
            String[] base64Str = data.split(",");
            bitmap = base64ToBitmap(base64Str[1], context);
        }
        return bitmap;
    }

    /**
     * 保存bitmap至本地
     *
     * @param image
     * @return
     */
    @SuppressLint("DefaultLocale")
    public static Observable<File> bitmapSaveFileToStorage(Bitmap image) {
        return Observable.create((ObservableOnSubscribe<File>) emitter -> {
            OutputStream output = null;
            try {
                File file = FileUtils.getFile("image", "jpg");
                output = new BufferedOutputStream(new FileOutputStream(file));
                image.compress(Bitmap.CompressFormat.JPEG, 90, output);
                output.flush();
                emitter.onNext(file);
                emitter.onComplete();
            } catch (Exception e) {
                e.printStackTrace();
                emitter.onError(e);
            } finally {
                try {
                    if (output != null) {
                        output.flush();
                        output.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).subscribeOn(Schedulers.io());
    }


    /**
     * 保存bitmap至相册
     *
     * @param image
     * @return
     */
    @SuppressLint("DefaultLocale")
    public static Observable<File> bitmapSaveFileToGallery(Context context, Bitmap image) {
        return Observable.create((ObservableOnSubscribe<File>) emitter -> {
            Long mImageTime = System.currentTimeMillis();
            String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss.SSS").format(new Date(mImageTime));
            String SCREENSHOT_FILE_NAME_TEMPLATE = "qfyxt_%s.png";//图片名称，以"全房源系统"+时间戳命名
            String mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);

            final ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
                    + File.separator + "全房源系统"); //Environment.DIRECTORY_SCREENSHOTS:截图,图库中显示的文件夹名。"dh"
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
            values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
            values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
            values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
            values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
            values.put(MediaStore.MediaColumns.IS_PENDING, 1);

            ContentResolver resolver = context.getContentResolver();
            final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            try {
                // First, write the actual data for our screenshot
                try (OutputStream out = resolver.openOutputStream(uri)) {
                    if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                        throw new IOException("Failed to compress");
                    }
                }
                // Everything went well above, publish it!
                values.clear();
                values.put(MediaStore.MediaColumns.IS_PENDING, 0);
                values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
                resolver.update(uri, values, null, null);
                emitter.onNext(new File(mImageFileName));
            } catch (IOException e) {
                resolver.delete(uri, null, null);
                Log.d("Exception", e.toString());
                emitter.onError(e);
            }
        }).subscribeOn(Schedulers.io());
    }

    /**
     * 通过文件名删除相册中的图片
     *
     * @param context  应用上下文
     * @param fileName 要删除图片的文件名（包含扩展名）
     * @return true表示删除成功，false表示删除失败
     */
    public static boolean deleteImageByFileName(Context context, String fileName) {
        ContentResolver resolver = context.getContentResolver();
        String selection = MediaStore.MediaColumns.DISPLAY_NAME + " =? ";
        String[] selectionArgs = {fileName};
        Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

        int deleteResult = resolver.delete(uri, selection, selectionArgs);
        return deleteResult > 0;
    }


    /**
     * 保存bitmap数组至本地
     *
     * @param images
     * @return
     */
    @SuppressLint("DefaultLocale")
    public static Observable<File> bitmapSaveFileToStorage(List<Bitmap> images) {
        return Observable.create((ObservableOnSubscribe<File>) emitter -> {
            OutputStream output = null;
            try {
                for (Bitmap image : images) {
                    File file = FileUtils.getFile("image", "jpg");
                    output = new BufferedOutputStream(new FileOutputStream(file));
                    image.compress(Bitmap.CompressFormat.JPEG, 90, output);
                    output.flush();
                    emitter.onNext(file);
                }
                emitter.onComplete();
            } catch (Exception e) {
                e.printStackTrace();
                emitter.onError(e);
            } finally {
                try {
                    if (output != null) {
                        output.flush();
                        output.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).subscribeOn(Schedulers.io());
    }

    public static boolean isNeedCompress(Bitmap resource) {
        int realLength = Util.getBitmapByteSize(resource.getWidth(), resource.getHeight(), Bitmap.Config.RGB_565);
        return realLength > IMAGE_LENGTH_LIMIT;
    }

    public static final int IMAGE_LENGTH_LIMIT = 6291456;

    public static byte[] bitmap2Bytes(Bitmap resource) {
        int realLength = Util.getBitmapByteSize(resource.getWidth(), resource.getHeight(), Bitmap.Config.RGB_565);
        float options = 0.9f;
        int scaleWidth = (int) (resource.getWidth() * options);
        int scaleHeight = (int) (resource.getHeight() * options);
        int scaleLength = Util.getBitmapByteSize(scaleWidth, scaleHeight, Bitmap.Config.RGB_565);
        while (scaleLength > IMAGE_LENGTH_LIMIT && options != 0.1) {
            options -= 0.1f;
            scaleWidth = (int) (scaleWidth * options);
            scaleHeight = (int) (scaleHeight * options);
            scaleLength = scaleWidth * scaleHeight * 2;
        }
        Bitmap scaleBitmap = Bitmap.createScaledBitmap(resource, scaleWidth, scaleHeight, true);
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        int quality = (int) (IMAGE_LENGTH_LIMIT * 1f / realLength * 100);
        if (quality < 90) {
            quality = 90;
        }
        resource.compress(Bitmap.CompressFormat.JPEG, quality, output);
        output.reset();
        scaleBitmap.compress(Bitmap.CompressFormat.JPEG, 85, output);
        return output.toByteArray();
    }

    public static Bitmap byte2Bitmap(byte[] data) {
        return BitmapFactory.decodeByteArray(data, 0, data.length);
    }

    public static void saveVideoToAlbumAfterQ(Context context, String videoFile) {
        try {
            ContentResolver contentResolver = context.getContentResolver();
            File tempFile = new File(videoFile);
            ContentValues contentValues = getVideoContentValues(context, tempFile, System.currentTimeMillis());
            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
                    + File.separator + "全房源系统"); //Environment.DIRECTORY_SCREENSHOTS:截图,图库中显示的文件夹名。"dh"
            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, tempFile.getName());
            Uri uri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
            copyFileAfterQ(context, contentResolver, tempFile, uri);
            contentValues.clear();
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
            context.getContentResolver().update(uri, contentValues, null, null);
            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过文件名删除相册中的图片
     *
     * @param context  应用上下文
     * @param fileName 要删除图片的文件名（包含扩展名）
     * @return true表示删除成功，false表示删除失败
     */
    public static boolean deleteVideoByFileName(Context context, String fileName) {
        ContentResolver resolver = context.getContentResolver();
        String selection = MediaStore.MediaColumns.DISPLAY_NAME + " =? ";
        String[] selectionArgs = {fileName};
        Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

        int deleteResult = resolver.delete(uri, selection, selectionArgs);
        return deleteResult > 0;
    }

    /**
     * 获取视频的contentValue
     */
    public static ContentValues getVideoContentValues(Context context, File paramFile, long timestamp) {
        ContentValues localContentValues = new ContentValues();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            localContentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM
                    + File.separator + context.getPackageName());
        }
        localContentValues.put(MediaStore.Video.Media.TITLE, paramFile.getName());
        localContentValues.put(MediaStore.Video.Media.DISPLAY_NAME, paramFile.getName());
        localContentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
        localContentValues.put(MediaStore.Video.Media.DATE_TAKEN, timestamp);
        localContentValues.put(MediaStore.Video.Media.DATE_MODIFIED, timestamp);
        localContentValues.put(MediaStore.Video.Media.DATE_ADDED, timestamp);
        localContentValues.put(MediaStore.Video.Media.SIZE, paramFile.length());
        return localContentValues;
    }

    private static void copyFileAfterQ(Context context, ContentResolver localContentResolver, File tempFile, Uri localUri) throws IOException {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q) {
            //拷贝文件到相册的uri,android10及以上得这么干，否则不会显示。可以参考ScreenMediaRecorder的save方法
            OutputStream os = localContentResolver.openOutputStream(localUri);
            Files.copy(tempFile.toPath(), os);
            os.close();
            tempFile.delete();
        }
    }

}
